import os
import pandas as pd
import re
from collections import defaultdict
from datetime import datetime
import logging

# 配置日志记录
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 获取桌面路径
def get_desktop_path():
    """获取当前用户的桌面路径"""
    return os.path.join(os.path.expanduser("~"), "Desktop")

# 读取Excel课表文件
def read_excel_file(file_path):
    """读取Excel文件并返回数据，支持.xls和.xlsx格式"""
    try:
        # 获取文件扩展名
        file_ext = os.path.splitext(file_path)[1].lower()
        
        if file_ext == '.xlsx' or file_ext == '.xlsm':
            # 对于.xlsx文件，使用openpyxl引擎
            df = pd.read_excel(file_path, engine='openpyxl')
        elif file_ext == '.xls':
            # 对于.xls文件，使用xlrd引擎
            df = pd.read_excel(file_path, engine='xlrd')
        else:
            print(f"不支持的文件格式: {file_ext}")
            return None
        
        if df.empty:
            print(f"文件 {file_path} 为空")
            return None
            
        return df
    except Exception as e:
        print(f"读取文件 {file_path} 时出错: {e}")
        return None

# 判断是否为有效的课程名称
def is_valid_course(course_name):
    """判断是否为有效的课程名称"""
    # 排除明显不是课程名称的内容
    invalid_keywords = ['星期', '内容顺序', '老师', '教师', '地点', '时间', '人数', '上午', '下午', '晚上', '课表']
    
    # 排除专业名称或院系名称
    major_department_names = ['人文', '国旅', '国贸', '财管', '板块', '马院', '计算机', '电子', '通信', '自动化', '机械', '土木', '建筑', '化工', '材料', '环境', '生物', '医学', '药学', '护理', '口腔', '临床', '基础医学', '预防医学', '公共卫生', '检验', '影像', '康复', '麻醉', '心理', '教育', '中文', '外语', '英语', '日语', '韩语', '法语', '德语', '俄语', '西班牙语', '国际', '贸易', '经济', '金融', '会计', '管理', '工商', '营销', '人力', '物流', '旅游', '酒店', '烹饪', '艺术', '音乐', '美术', '设计', '服装', '舞蹈', '体育']
    
    valid_min_length = 2
    valid_max_length = 50
    
    # 检查长度
    if len(course_name) < valid_min_length or len(course_name) > valid_max_length:
        return False
    
    # 检查是否包含无效关键词
    if any(keyword in course_name for keyword in invalid_keywords):
        return False
    
    # 检查是否为专业或院系名称
    if course_name in major_department_names:
        return False
    
    # 检查是否只包含特殊字符或数字
    if re.match(r'^[\d\s\W]+$', course_name):
        return False
    
    return True

# 判断是否为有效的教师名称
def is_valid_teacher(teacher_name):
    """判断是否为有效的教师名称"""
    # 排除明显不是教师名称的内容
    invalid_keywords = ['星期', '内容顺序', '老师', '教师', '地点', '时间', '人数', '周', '节', '课程', '教育', '实践', '理论', '安全', '体育', '英语', '思想', '道德', '法治', '概论', '主义', '理论体系', '特色社会主义', '海南', '自由贸易港']
    
    # 检查长度
    if len(teacher_name) < 2 or len(teacher_name) > 10:
        return False
    
    # 检查是否包含无效关键词
    if any(keyword in teacher_name for keyword in invalid_keywords):
        return False
    
    # 检查是否包含过多数字（教师名称通常以中文为主，不应包含太多数字）
    if sum(c.isdigit() for c in teacher_name) > 0:
        return False
    
    # 检查是否包含特殊字符
    special_chars = r'[\/\*\-\+\(\)\[\]\{\}\s\.,;:!@#\$%\^&\*]'
    if re.search(special_chars, teacher_name):
        return False
    
    # 确保只包含汉字（教师姓名通常由姓和名组成）
    if not re.match(r'^[\u4e00-\u9fa5]+$', teacher_name):
        return False
    
    return True

# 从DataFrame中提取课程和老师信息
def extract_course_info(df, file_name):
    """从DataFrame中提取课程和老师信息"""
    courses = []
    course_names = set()
    
    # 转换所有数据为字符串类型
    df = df.astype(str).apply(lambda x: x.str.strip())
    
    # 定义可能的课程和老师关键词
    course_keywords = ['课程', '科目', 'subject', 'course']
    teacher_keywords = ['教师', '老师', 'instructor', 'teacher']
    
    # 查找包含课程和老师信息的列
    course_cols = []
    teacher_cols = []
    
    # 检查列名
    for col in df.columns:
        col_lower = col.lower()
        for keyword in course_keywords:
            if keyword.lower() in col_lower:
                course_cols.append(col)
                break
        for keyword in teacher_keywords:
            if keyword.lower() in col_lower:
                teacher_cols.append(col)
                break
    
    # 如果找到了明确的课程和老师列，直接处理
    if course_cols and teacher_cols:
        print(f"找到明确的课程列和老师列，开始提取数据")
        for _, row in df.iterrows():
            for course_col in course_cols:
                for teacher_col in teacher_cols:
                    course_value = row[course_col]
                    teacher_value = row[teacher_col]
                    
                    # 过滤空值和无效数据
                    if course_value != 'nan' and teacher_value != 'nan' and course_value and teacher_value:
                        # 清理数据
                        course_name = re.sub(r'\s+', ' ', course_value.strip())
                        teacher_name = re.sub(r'\s+', ' ', teacher_value.strip())
                        
                        # 过滤无效的课程名和老师名
                        if is_valid_course(course_name) and is_valid_teacher(teacher_name):
                            courses.append({
                                'course': course_name,
                                'teacher': teacher_name,
                                'file': file_name
                            })
                            course_names.add(course_name)
    else:
        # 如果没有找到明确的列，尝试扫描所有单元格中的模式
        print(f"未找到明确的课程和老师列，尝试从单元格内容中识别模式")
        
        # 定义更精确的正则表达式模式
        patterns = [
            # 模式1: 课程名称<>周次<>地点<>教师（格式如：课程<>1-18周<>教室<>教师）
            r'(.*?)<>.*?<>.*?<>(.*?)',
            # 模式2: 课程名称(教师姓名)（格式如：高等数学(张三)）
            r'(.*?)\(([\u4e00-\u9fa5]{2,})\)',
            # 模式3: 教师姓名：课程名称（格式如：张三：高等数学）
            r'([\u4e00-\u9fa5]{2,})：(.*?)',
            # 模式4: 课程名称/教师姓名（格式如：高等数学/张三）
            r'(.*?)/([\u4e00-\u9fa5]{2,})',
            # 模式5: 课程名称 ★ 教师姓名（格式如：高等数学 ★ 张三）
            r'(.*?)[★☆]([\u4e00-\u9fa5]{2,})',
        ]
        
        for _, row in df.iterrows():
            for col in df.columns:
                cell_value = str(row[col])
                
                # 跳过空值和无效数据
                if cell_value == 'nan' or not cell_value.strip():
                    continue
                
                # 尝试所有模式
                for pattern in patterns:
                    matches = re.finditer(pattern, cell_value)
                    for match in matches:
                        if len(match.groups()) >= 2:
                            # 对于不同模式，组的顺序可能不同
                            if '☆' in pattern or '★' in pattern or '/' in pattern and '教师' not in cell_value:
                                # 课程在前，教师在后的模式
                                course_name = match.group(1).strip()
                                teacher_name = match.group(2).strip()
                            else:
                                # 教师在前，课程在后的模式
                                teacher_name = match.group(1).strip()
                                course_name = match.group(2).strip()
                            
                            # 过滤无效数据
                            if is_valid_course(course_name) and is_valid_teacher(teacher_name):
                                courses.append({
                                    'course': course_name,
                                    'teacher': teacher_name,
                                    'file': file_name
                                })
                                course_names.add(course_name)
                                break  # 找到一个匹配后就不再尝试其他模式
                    
                    # 尝试识别地点/教师/人数格式（如：第一教室/张三/45）
                    location_teacher_pattern = r'.*?/([\u4e00-\u9fa5]{2,})/\d+'
                    match = re.search(location_teacher_pattern, cell_value)
                    if match and len(match.groups()) >= 1:
                        # 从其他位置尝试提取课程名
                        possible_course = re.search(r'(^[^/]+)', cell_value)
                        if possible_course:
                            course_name = possible_course.group(1).strip()
                            teacher_name = match.group(1).strip()
                            
                            if is_valid_course(course_name) and is_valid_teacher(teacher_name):
                                courses.append({
                                    'course': course_name,
                                    'teacher': teacher_name,
                                    'file': file_name
                                })
                                course_names.add(course_name)
    
    # 去重 - 使用更严格的去重逻辑
    unique_courses = []
    seen = set()
    for course in courses:
        # 生成更稳定的去重键
        clean_course = re.sub(r'[\s\-_]+', '', course['course'].lower())
        clean_teacher = re.sub(r'[\s\-_]+', '', course['teacher'].lower())
        key = f"{clean_course}_{clean_teacher}"
        
        if key not in seen:
            seen.add(key)
            unique_courses.append(course)
    
    print(f"从文件 {file_name} 中提取了 {len(unique_courses)} 门有效课程")
    return unique_courses, list(course_names)

# 整理课程列表
def organize_course_list(all_courses):
    """整理课程列表，只提取纯课程名称并排序"""
    # 使用is_valid_course函数进行过滤
    valid_courses = []
    seen_patterns = set()
    
    for course in all_courses:
        course_name = course['course']
        
        if is_valid_course(course_name):
            # 提取纯课程名称，去除时间地点等信息
            # 假设课程名和时间地点用'/'分隔，取第一个部分
            pure_course_name = course_name.split('/')[0].strip()
            clean_course = re.sub(r'\s+', ' ', pure_course_name)
            
            # 生成模式字符串用于去重（忽略特殊字符）
            course_pattern = re.sub(r'[\/\*\-\+\(\)\[\]\{\}\s]', '', clean_course.lower())
            if course_pattern and len(course_pattern) > 1 and course_pattern not in seen_patterns:
                valid_courses.append(clean_course)
                seen_patterns.add(course_pattern)
    
    # 按名称排序
    valid_courses.sort()
    return valid_courses

# 整理教师授课列表
def organize_teacher_courses(all_courses):
    """整理教师授课列表，按教师分组，只显示纯课程名称"""
    teacher_courses = defaultdict(set)
    
    for course in all_courses:
        teacher = course['teacher']
        course_name = course['course']
        
        # 使用更严格的过滤函数
        if is_valid_teacher(teacher) and is_valid_course(course_name):
            # 清理教师名称
            clean_teacher = re.sub(r'\s+', ' ', teacher.strip())
            
            # 提取纯课程名称，去除时间地点等信息
            # 假设课程名和时间地点用'/'分隔，取第一个部分
            pure_course_name = course_name.split('/')[0].strip()
            
            teacher_courses[clean_teacher].add(pure_course_name)
    
    # 转换为列表并排序
    result = {}
    for teacher, courses in teacher_courses.items():
        # 只保留至少有一门课程的老师
        if courses:
            result[teacher] = sorted(list(courses))
    
    return result

# 打印课程列表
def print_course_list(courses):
    """打印整理后的课程列表"""
    print("\n="*30)
    print("整理后的课程列表".center(50))
    print("="*60)
    
    if not courses:
        print("\n未找到有效的课程信息")
    else:
        for i, course in enumerate(courses, 1):
            print(f"{i:2d}. {course}")
        print(f"\n总课程数: {len(courses)}")
    
    print("="*60)

# 打印教师授课列表
def print_teacher_courses(teacher_courses):
    """打印整理后的教师授课列表"""
    print("\n="*30)
    print("整理后的教师授课列表".center(50))
    print("="*60)
    
    if not teacher_courses:
        print("\n未找到有效的教师授课信息")
    else:
        # 按教师姓名排序
        sorted_teachers = sorted(teacher_courses.keys())
        
        for i, teacher in enumerate(sorted_teachers, 1):
            courses = teacher_courses[teacher]
            print(f"\n{i:2d}. {teacher} 老师 ({len(courses)} 门课程):")
            for course in courses:
                print(f"    └─ {course}")
        
        print(f"\n总授课教师数: {len(teacher_courses)}")
    
    print("="*60)

# 保存结果到文件
def save_results_to_file(all_courses, course_list, teacher_courses):
    """保存整理结果到文件"""
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filepath = os.path.join(os.getcwd(), f"课程整理结果_{timestamp}.txt")
    
    try:
        with open(filepath, 'w', encoding='utf-8') as f:
            # 写入课程列表
            f.write("============================================================\n")
            f.write("                    课程列表\n")
            f.write("============================================================\n")
            for i, course in enumerate(course_list, 1):
                f.write(f"{i}. {course}\n")
            f.write(f"\n总课程数: {len(course_list)}\n")
            f.write("============================================================\n\n\n")
            
            # 写入教师授课列表
            f.write("============================================================\n")
            f.write("                   教师授课列表\n")
            f.write("============================================================\n")
            for i, (teacher, courses) in enumerate(sorted(teacher_courses.items()), 1):
                f.write(f"{i}. {teacher} ({len(courses)} 门课程):\n")
                for course in courses:
                    f.write(f"    └─ {course}\n")
                f.write("\n")
            f.write(f"总授课教师数: {len(teacher_courses)}\n")
            f.write("============================================================\n")
        print(f"\n结果已保存到: {filepath}")
        return filepath
    except Exception as e:
        print(f"保存文件时出错: {e}")
        return None

# 主函数
def main():
    print("="*60)
    print("课程信息整理程序".center(50))
    print("="*60)
    print("功能：1.整理课程列表  2.整理教师授课列表")
    print("="*60)
    
    # 获取当前目录下的课表文件
    current_dir = os.getcwd()
    course_files = []
    
    # 查找.xls和.xlsx文件
    for filename in os.listdir(current_dir):
        if filename.endswith('.xls') or filename.endswith('.xlsx'):
            # 排除临时文件
            if not filename.startswith('~$'):
                course_files.append(os.path.join(current_dir, filename))
    
    if not course_files:
        print("\n未找到课表文件，请确保当前目录下存在.xls或.xlsx格式的课表文件")
        return
    
    print(f"\n找到 {len(course_files)} 个课表文件:")
    for i, file_path in enumerate(course_files, 1):
        print(f"{i}. {os.path.basename(file_path)}")
    
    # 解析所有文件中的课程信息
    all_courses = []
    all_course_names = set()
    
    for file_path in course_files:
        file_name = os.path.basename(file_path)
        print(f"\n正在处理文件: {file_name}")
        
        # 读取Excel文件
        df = read_excel_file(file_path)
        
        if df is not None:
            print(f"  文件读取成功，包含 {len(df)} 行数据")
            # 提取课程信息
            courses, course_names = extract_course_info(df, file_name)
            all_courses.extend(courses)
            all_course_names.update(course_names)
        else:
            print(f"  警告: 文件读取失败或为空")
    
    print(f"\n总共从所有文件中提取了 {len(all_courses)} 条课程记录")
    
    if not all_courses:
        print("\n未能从文件中提取出有效的课程信息")
        print("建议检查：")
        print("1. 课表文件格式是否正确")
        print("2. 表格中是否包含课程和老师信息")
        return
    
    # 整理课程列表
    organized_courses = organize_course_list(all_courses)
    print_course_list(organized_courses)
    
    # 整理教师授课列表
    teacher_courses = organize_teacher_courses(all_courses)
    print_teacher_courses(teacher_courses)
    
    # 保存结果到文件
    save_results_to_file(all_courses, organized_courses, teacher_courses)
    
    print("\n程序运行完成！")

if __name__ == "__main__":
    main()